package com.matrix.storage.utils;


import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.*;
import com.matrix.storage.properties.AliOSSProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.ByteArrayInputStream;
import java.util.List;

@Component
public class AliOssUtil {

    @Autowired
    private AliOSSProperties aliProperties;

    private OSS openOSSClient() {
        OSS tmpOssClient = new OSSClientBuilder().build(aliProperties.getEndpoint(),
                aliProperties.getAccessKeyId(), aliProperties.getAccessKeySecret());
        return tmpOssClient;
    }

    private void shutdownOSSClient(OSS ossClient)  {
        if (ossClient != null) {
            ossClient.shutdown();
        }
    }

    public String bucketName () {
        return aliProperties.getBucketName();
    }

    public String endPoint() {
        return aliProperties.getEndpoint();
    }

    /**
     * 创建Bucket
     * @param bucketName
     */
    public void createBucket(String bucketName) {
        OSS ossClient = openOSSClient();
        try {
            // 创建CreateBucketRequest对象。
            CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
            // 设置存储空间读写权限为公共读，默认为私有。
            createBucketRequest.setCannedACL(CannedAccessControlList.PublicReadWrite);
            // 创建存储空间。
            ossClient.createBucket(createBucketRequest);
        } catch (OSSException oe) {
            handleOSSException(oe);
        } catch (ClientException ce) {
            handleClientException(ce);
        } finally {
            shutdownOSSClient(ossClient);
        }
    }

    /**
     * 在bucket中，创建文件夹
     * @param folderName 文件夹名称
     */
    public void createFolder(String folderName) {
        if (!folderName.isEmpty()) {
            OSS ossClient = openOSSClient();
            String fullFolderName;
            char lastChar = folderName.charAt(folderName.length() - 1);
            if (lastChar != '/') {
                fullFolderName = folderName + "/";
            } else {
                fullFolderName = folderName;
            }
            try {
                String content = "";
                PutObjectRequest putObjectRequest = new PutObjectRequest(aliProperties.getBucketName(), fullFolderName, new ByteArrayInputStream(content.getBytes()));
                ossClient.putObject(putObjectRequest);
            } catch (OSSException oe) {
                handleOSSException(oe);
            } catch (ClientException ce) {
                handleClientException(ce);
            } finally {
                shutdownOSSClient(ossClient);
            }
        }
    }

    /**
     * 获取存储空间
     * @throws OSSException
     */
    public void queryBucketInfoStat() {
        String bucketName = aliProperties.getBucketName();
        OSS ossClient = openOSSClient();
        try {
            BucketStat stat = ossClient.getBucketStat(bucketName);
            // 获取Bucket的总存储量，单位为字节。
            Long storageSize = stat.getStorageSize();
            String storageSizeStr = FileUtil.fileSizeStr(storageSize);
            System.out.println(storageSizeStr);
        } catch (OSSException oe) {
            handleOSSException(oe);
        } catch (ClientException ce) {
            handleClientException(ce);
        } finally {
            shutdownOSSClient(ossClient);
        }
    }

    /**
     * 以下代码用于通过GetBucketV2 (ListObjectsV2)方法列举指定存储空间下的文件，默认列举100个文件。
     * @param keyPrefix 指定前缀，例如exampledir/object
     * @return
     */
    public List<OSSObjectSummary> listObjectsV2(String keyPrefix) {
        String bucketName = aliProperties.getBucketName();
        // 创建OSSClient实例。
        OSS ossClient = openOSSClient();
        try {
            // 列举文件。如果不设置keyPrefix，则列举存储空间下的所有文件。如果设置keyPrefix，则列举包含指定前缀的文件。
            ListObjectsV2Result result = ossClient.listObjectsV2(bucketName, keyPrefix);
            List<OSSObjectSummary> ossObjectSummaries = result.getObjectSummaries();
            return ossObjectSummaries;

        } catch (OSSException oe) {
            handleOSSException(oe);
            return null;
        } catch (ClientException ce) {
            handleClientException(ce);
            return null;
        } finally {
            shutdownOSSClient(ossClient);
        }
    }

    /**
     * 文件上传
     *
     * @param bytes
     * @param objectName
     * @return
     */
    public String upload(byte[] bytes, String objectName) {

        String bucketName = aliProperties.getBucketName();
        String endPoint = aliProperties.getEndpoint();

        // 创建OSSClient实例。
        OSS ossClient = openOSSClient();
        try {
            // 创建PutObject请求。
            ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(bytes));
        } catch (OSSException oe) {
            handleOSSException(oe);
        } catch (ClientException ce) {
            handleClientException(ce);
        } finally {
            shutdownOSSClient(ossClient);
        }

        //文件访问路径规则 https://BucketName.Endpoint/ObjectName
        StringBuilder stringBuilder = new StringBuilder("https://");
        stringBuilder
                .append(bucketName)
                .append(".")
                .append(endPoint)
                .append("/")
                .append(objectName);

        return stringBuilder.toString();
    }

    private void handleOSSException(OSSException oe) {
        System.out.println("Caught an OSSException, which means your request made it to OSS, "
                + "but was rejected with an error response for some reason.");
        System.out.println("Error Message:" + oe.getErrorMessage());
        System.out.println("Error Code:" + oe.getErrorCode());
        System.out.println("Request ID:" + oe.getRequestId());
        System.out.println("Host ID:" + oe.getHostId());
    }

    private void handleClientException(ClientException ce) {
        System.out.println("Caught an OSSException, which means your request made it to OSS, "
                + "but was rejected with an error response for some reason.");
        System.out.println("Error Message:" + ce.getErrorMessage());
        System.out.println("Error Code:" + ce.getErrorCode());
        System.out.println("Request ID:" + ce.getRequestId());
    }
}
